//
//  Interface.cpp
//  Dungeons and Princesses
//
//  Created by John Grange on 10/22/11.
//  Copyright (c) 2011 SD Networks. All rights reserved.
//

#include <iostream>
#include "Interface.h"


using namespace Attack;

// initialize static strings
const std::string Interface::VERSION = "Dungeons and Princeses v.04";
const std::string Interface::WELCOMEMSG = "Welcome to Dungeons and Princesses, please take a momment to familiarize your self with this new enviroment.";


Interface::Interface(Game *ptrToCurrentGame) {

    gamePtr = ptrToCurrentGame;

}


void Interface::move(string direction)
{
    string id;
    Direction * ddirection = gamePtr->getCurrentRoom()->getDirection(direction);
    if (ddirection->getRoomID() == "Locked")
    {
        update("The Door is locked.");
    }
    else if (ddirection->getRoomID() != "null")
    {
        id = ddirection->getRoomID();
        gamePtr->setCurrentRoom(gamePtr->getCastle()->getRoom(id));
        
        if (!gamePtr->getCurrentRoom()->getVisited())
        {
            gamePtr->randomMonster();
        }
        
        update();
    }
    else {
        update("You can not go this direction");
    }
}

bool Interface::unlock(string direction)
{
    bool result = false;
    string msg;
    if(hasDoor(direction))
    {
        vector<Listing>const * playerInventory = gamePtr->getCurrentPlayer()->inventory.getManifest();
        Key *k;
        for (int index = 0; index < playerInventory->size(); index++)
        {
            if(playerInventory->at(index).objectType.compare("Key") == 0)
            {
                k = gamePtr->getCurrentPlayer()->inventory.getKey(playerInventory->at(index).objectID);
                gamePtr->getCurrentRoom()->getDirection(direction)->getDoor()->unlock(k->getKeyCode());
                gamePtr->getCurrentPlayer()->inventory.add(k);
                if(!gamePtr->getCurrentRoom()->getDirection(direction)->getDoor()->isLocked())
                    break;
            }
        }
        if(!gamePtr->getCurrentRoom()->getDirection(direction)->getDoor()->isLocked())
        {
            msg = "You have unlocked the door to the " + direction;
            result = true;
        }
        else
        {
            msg = "You do not have the key to the door to the " + direction;
            result = false;
        }
    }
    update(msg);
    return result;
}

bool Interface::hasDoor(string direction)
{
     return gamePtr->getCurrentRoom()->getDirection(direction)->getHasDoor();
}

bool Interface::pickUp(string itemToPickUp)
{
    int count = 0;
    string des;
    long found;
    int objectID[10];
    string objectType[10];

    vector<Listing>const * roomInventory = gamePtr->getCurrentRoom()->getManifest();

    for (int index = 0; index < roomInventory->size(); index++)
    {
        des = roomInventory->at(index).description;

        des = Utility::lowerCase(des);

        found = des.find(Utility::removeGarbage(itemToPickUp));

        //found = des.find("Rusty");
        if (found != string::npos)
        {
            objectID[count] = roomInventory->at(index).objectID;
            objectType[count] = roomInventory->at(index).objectType;
            count++;
        }
    }

    if (count == 1) {

        string response = getObject(objectType[0], objectID[0]);

        update(response);
        return true;
    }
    else if( count < 1 )
    {
        update("There is no such object in this room, try again");
        return false;
    }
    return true;
}

void Interface::dropItem(string itemToBeDropped)
{
    vector<Listing>const * playerInventory = gamePtr->getCurrentPlayer()->inventory.getManifest();
    string des;
    long found;
    int objectID[10];
    string objectType[10];
    int count = 0;
    for (int index = 0; index < playerInventory->size(); index++)
    {
        des = playerInventory->at(index).description;

        des = Utility::lowerCase(des);

        found = des.find(Utility::removeGarbage(itemToBeDropped));

        //found = des.find("Rusty");
        if (found != string::npos)
        {
            objectID[count] = playerInventory->at(index).objectID;
            objectType[count] = playerInventory->at(index).objectType;
            count++;
        }
        else if( count < 1 )
        {
            update("There is no such object in your inventory, try again");
        }
    }

    if (count == 1) {

        string response = dropObject(objectType[0], objectID[0]);

        update(response);

    }


}


string Interface::dropObject(std::string objectType, int objectID) {

    if (objectType == "Key") {

        Key * tmpKey = gamePtr->getCurrentPlayer()->inventory.getKey(objectID);

        gamePtr->getCurrentRoom()->add(tmpKey);

        // send back the message to the interface that you succesfully picked up the object
        // We are using stringstream here to avoid a possible buffer overflow.

        stringstream msg;

        string msgPrefix = "You removed the ";

        string msgPostfix = ", from your inventory and dropped it in this room";

        msg << msgPrefix << tmpKey->getDesc() << msgPostfix;

        return msg.str();
    }
    else if (objectType == "Potion") {

        Potion *tmpPotion  = gamePtr->getCurrentPlayer()->inventory.getPotion(objectID);
        gamePtr->getCurrentRoom()->add(tmpPotion);

        // send back the message to the interface that you succesfully picked up the object
        // We are using stringstream here to avoid a possible buffer overflow.

        stringstream msg;

        string msgPrefix = "You removed the ";

        string msgPostfix = ", from your inventory and dropped it in this room";

        msg << msgPrefix << tmpPotion->getDesc() << msgPostfix;

        return msg.str();
    }

    else if (objectType == "Equipment") {

        EquipmentType *tmpEquipment  = gamePtr->getCurrentPlayer()->inventory.getEquipmentType(objectID);
        gamePtr->getCurrentRoom()->add(tmpEquipment);

        // send back the message to the interface that you succesfully picked up the object
        // We are using stringstream here to avoid a possible buffer overflow.

        stringstream msg;

        string msgPrefix = "You removed the ";

        string msgPostfix = ", from your inventory and dropped it in this room";

        msg << msgPrefix << tmpEquipment->getDesc() << msgPostfix;

        return msg.str();

    }
    else {

        string msg = "ERROR**** Invalid somethign really wierd happend ****";

        return msg;
    }
}

bool Interface::equipObject(string objectToEquip) {
    
    vector<Listing>const * objectsMatching = gamePtr->getCurrentPlayer()->inventory.hasObjectInInventory(objectToEquip);
    
    if (objectsMatching->size() == 1) {
        
        EquipmentType * itemToEquip = gamePtr->getCurrentPlayer()->inventory.getEquipmentType(objectsMatching->at(0).objectID);
        
        string error;
        return gamePtr->getCurrentPlayer()->equip(itemToEquip, error);
        
    }
#warning we need code here to deal with more than 1 item too
    else {
        
        return false;
    }
}

#warning Shouldn't this be in inventory maybe??
void Interface::dropAll() {

    vector<Listing>const * playerInventory = gamePtr->getCurrentPlayer()->inventory.getManifest();
    // drop all

    long itemsInInventory = playerInventory->size();

    for (long i = 0; i < itemsInInventory; i++) {

        dropObject(playerInventory->at(0).objectType, playerInventory->at(0).objectID);
    }
}

std::string Interface::getObject(std::string objectType, int objectID) {

    if (objectType == "Key") {

        Key * tmpKey = gamePtr->getCurrentRoom()->getKey(objectID);

        gamePtr->getCurrentPlayer()->inventory.add(tmpKey);

        // send back the message to the interface that you succesfully picked up the object
        // We are using stringstream here to avoid a possible buffer overflow.

        stringstream msg;

        string msgPrefix = "You picked up the ";

        string msgPostfix = ", and placed it in your inventory";

        msg << msgPrefix << tmpKey->getDesc() << msgPostfix;

        return msg.str();
    }
    else if (objectType == "Potion") {

        Potion *tmpPotion  = gamePtr->getCurrentRoom()->getPotion(objectID);
        gamePtr->getCurrentPlayer()->inventory.add(tmpPotion);

        // send back the message to the interface that you succesfully picked up the object
        // We are using stringstream here to avoid a possible buffer overflow.

        stringstream msg;

        string msgPrefix = "You picked up the ";

        string msgPostfix = ", and placed it in your inventory";

        msg << msgPrefix << tmpPotion->getDesc() << msgPostfix;

        return msg.str();

    }

    else if (objectType == "Equipment") {

        EquipmentType *tmpEquipment  = gamePtr->getCurrentRoom()->getEquipmentType(objectID);
        gamePtr->getCurrentPlayer()->inventory.add(tmpEquipment);

        // send back the message to the interface that you succesfully picked up the object
        // We are using stringstream here to avoid a possible buffer overflow.

        stringstream msg;

        string msgPrefix = "You picked up the ";

        string msgPostfix = ", and placed it in your inventory";

        msg << msgPrefix << tmpEquipment->getDesc() << msgPostfix;

        return msg.str();

    }
    else {

        string msg = "ERROR**** Invalid somethign really wierd happend ****";

        return msg;
    }

}
void Interface::attack(string monsterToAttack)
{
    vector<Listing>const * roomInventory = gamePtr->getCurrentRoom()->getManifest();

    string des;
    long found;
    int objectID[10];
    string objectType[10];
    int count = 0;

    for (int index = 0; index < roomInventory->size(); index++)
    {
        des = roomInventory->at(index).description;

        des = Utility::lowerCase(des);
#warning fix hardcoded command AND add more checking for errors
        found = des.find(Utility::removeGarbage(monsterToAttack));

        //found = des.find("Rusty");
        if (found != string::npos)
        {
            objectID[count] = roomInventory->at(index).objectID;
            objectType[count] = roomInventory->at(index).objectType;
            count++;
        }
    }

    Monster *ourMonster = gamePtr->getCurrentRoom()->getMonster(objectID[0]);
    
    // following code was added to test out new doAttack method which takes a pointer
    // interface people should change as needed
    const vector<AttackType>* abilities= gamePtr->getCurrentPlayer()->getAttacks();


    doAttack(gamePtr->getCurrentPlayer(), ourMonster, abilities->at(0));
}

void Interface::attack(Monster *monsterToAttack, AttackType attackToUse) {
    doAttack(gamePtr->getCurrentPlayer(), monsterToAttack, attackToUse);
}

string Interface::getCurrentRoomDescription()
{
    string desc = gamePtr->getCurrentRoom()->getDesc();

    for (int directionNum = 0; directionNum < 4; directionNum++) {

        if(gamePtr->getCurrentRoom()->getDirections()[directionNum].getDesc().compare("null") != 0)
        {
            desc = desc + ' ' + gamePtr->getCurrentRoom()->getDirections()[directionNum].getDesc() + "\n";
        }
        if(gamePtr->getCurrentRoom()->getDirections()[directionNum].getHasDoor())
            desc = desc + ' ' + gamePtr->getCurrentRoom()->getDirections()[directionNum].getDoor()->getDesc() + "\n";
    }

    return desc;
}
